import * as path from 'path'
import * as fs from 'fs'
import { Injectable } from '@nestjs/common'

@Injectable()
export class RepositoryService<T> {

  public fileName: string
  public primaryKey: string
  public get filePath() {
    return path.join(__dirname, '../../data/' + this.fileName)
  }

  constructor(fileName: string, primaryKey: string) {
    this.fileName = fileName
    this.primaryKey = primaryKey
  }


  public getAll() {
    let content = fs.readFileSync(this.filePath, { encoding: 'utf-8' }).toString()
    try {
      return JSON.parse(content) as T[]
    } catch (e) {
      console.error(e)
      throw new Error('数据文件内容有误，请检查修改后再试。')
    }
  }

  public findOneOrFail(predicate: (value: T, index: number, obj: T[]) => boolean) {
    let item = this.getAll().find(predicate)
    if (item) {
      return item
    }
    throw new Error('没有找到对应的数据')
  }

  public findIndexOneOrFail(predicate: (value: T, index: number, obj: T[]) => boolean) {
    let index = this.getAll().findIndex(predicate)
    if (index >= 0) {
      return index
    }
    throw new Error('没有找到对应的数据')
  }

  public add(model: T) {
    let items = this.getAll()
    if (items.find(n => n[this.primaryKey] === model[this.primaryKey])) {
      throw new Error('主键重复')
    }
    items.push(model)
    this.save(items)
  }

  public update(model: T) {
    let items = this.getAll()
    let index = this.findIndexOneOrFail(n => n[this.primaryKey] === model[this.primaryKey])
    items[index] = model
    this.save(items)
  }

  public updateByPrimaryKey(id: any, data: Partial<T>) {
    let items = this.getAll()
    let index = this.findIndexOneOrFail(n => n[this.primaryKey] === id)
    items[index] = { ...items[index], ...data }
    this.save(items)
  }

  public delete(id: any) {
    let items = this.getAll()
    let index = items.findIndex(n => n[this.primaryKey] === id)
    if (index < 0) {
      throw new Error('不存在的数据')
    }
    items.splice(index, 1)
    this.save(items)
  }

  public save(models: T[]) {
    let json = JSON.stringify(models, null, 2)
    fs.writeFileSync(this.filePath, json, { encoding: 'utf-8' })
  }

}
